from coin.exchange.kr_rest.product.product_impl import (BequantProduct,
                                                        BinanceFuturesProduct,
                                                        BinanceProduct,
                                                        BitfinexProduct,
                                                        BitflyerFuturesProduct,
                                                        BithumbProduct,
                                                        BitmexFuturesProduct,
                                                        BitstampProduct,
                                                        BybitFuturesProduct,
                                                        CoinoneProduct,
                                                        DeribitFuturesProduct,
                                                        FcoinProduct,
                                                        FTXFuturesProduct,
                                                        GdaxProduct,
                                                        GopaxProduct,
                                                        HitbtcProduct,
                                                        HuobiFuturesProduct,
                                                        HuobiProduct,
                                                        KorbitProduct,
                                                        KrakenFuturesProduct,
                                                        KrakenProduct,
                                                        OkexFuturesProduct,
                                                        OkexProduct,
                                                        QuoinexProduct,
                                                        UpbitProduct,
                                                        get_exchange_product_list_grouped)
from coin.strategy.mm.subscription import (
    FeedSubscriptionRequest,
    SubscriptionRequest,
    get_subscription_key,
)


def gen_all_products(trading_date):
  products = []

  # futures
  for base in ('BTC', 'ETH'):
    products.extend([
        BitmexFuturesProduct.FromStr('%s-USD.PERPETUAL' % base),
    ])

  bases = (
      'BTC', 'ETH', 'EOS', 'XRP', 'ETC', 'BCHABC', 'LTC', 'TRX', 'BCHSV',
      'LINK', 'DOT', 'ADA', 'XLM', 'ZEC', 'DASH', 'QTUM', 'BNB', 'XMR', 'IOST')
  expiries = ['THIS_WEEK', 'NEXT_WEEK', 'QUARTER', 'PERPETUAL']

  for base in bases:
    for expiry in expiries:
      p = OkexFuturesProduct.FromStrNothrow(f'{base}-USD.{expiry}', trading_date)
      if p is not None:
        products.append(p)

  for base in bases:
    for expiry in expiries:
      p = HuobiFuturesProduct.FromStrNothrow(f'{base}-USD.{expiry}', trading_date)
      if p is not None:
        products.append(p)

  for base in ['BTC', 'ETH', 'LINK']:
    for expiry in ['PERPETUAL', 'QUARTER']:
      p = FTXFuturesProduct.FromStrNothrow(f'{base}-USD.{expiry}', trading_date)
      if p is not None:
        products.append(p)

  for base in ['BTC']:
    for expiry in ['PERPETUAL']:
      p = BybitFuturesProduct.FromStrNothrow(f'{base}-USD.{expiry}', trading_date)
      if p is not None:
        products.append(p)

  products.extend([
      BitflyerFuturesProduct.FromStr("BTC-JPY.PERPETUAL"),
      BitflyerFuturesProduct.FromStr("BTC-JPY.IMMEDIATE"),
  ])

  for base in ('BTC', 'ETH', 'LTC', 'BCHABC', 'XRP'):
    products.extend([
        KrakenFuturesProduct.FromStr('%s-USD.MONTH' % base),
        KrakenFuturesProduct.FromStr('%s-USD.QUARTER' % base),
        KrakenFuturesProduct.FromStr('%s-USD.PERPETUAL' % base),
    ])

  for base in ('BTC', 'ETH'):
    products.extend([
        DeribitFuturesProduct.FromStr('%s-USD.QUARTER' % base),
        DeribitFuturesProduct.FromStr('%s-USD.NEXT_QUARTER' % base),
        DeribitFuturesProduct.FromStr('%s-USD.PERPETUAL' % base),
    ])

  for base in bases:
    try:
      products.extend([BinanceFuturesProduct.FromStr('%s-USDT.PERPETUAL' % base)])
    except:
      pass
    try:
      products.extend([BinanceFuturesProduct.FromStr('%s-USD.PERPETUAL' % base)])
    except:
      pass
    try:
      products.extend([BinanceFuturesProduct.FromStr('%s-USD.QUARTER' % base)])
    except:
      pass

  # spot
  for product_type in {
      # offshore
      BinanceProduct,
      OkexProduct,
      HuobiProduct,
      BitfinexProduct,
      HitbtcProduct,
      FcoinProduct,
      BitstampProduct,  # korea
      BithumbProduct,
      UpbitProduct,
      KorbitProduct,
      CoinoneProduct,
      GopaxProduct,  # japan
      BitflyerFuturesProduct,
      QuoinexProduct,  # us
      GdaxProduct,
      KrakenProduct,
      BitstampProduct,
      BequantProduct,
  }:
    for quote in ('USDT', 'USD', 'BTC', 'KRW', 'JPY', 'EUR'):
      for base in bases:
        symbol = '%s-%s' % (base, quote)
        p = product_type.FromStrNothrow(symbol)
        if p is not None:
          products.append(p)

  # Binance
  for quote in ('USDC', 'TUSD', 'PAX', 'USDS', 'BUSD'):
    for base in ('BTC', 'ETH', 'EOS', 'ETC', 'XRP', 'BCHABC', 'LTC', 'TRX', 'BCHSV'):
      symbol = '%s-%s' % (base, quote)
      p = BinanceProduct.FromStrNothrow(symbol)
      if p is not None:
        products.append(p)

  return products


def gen_btc_products(trading_date):
  products = []

  # futures
  products.extend([
      BitmexFuturesProduct.FromStr('BTC-USD.PERPETUAL'),
  ])

  products.extend([
      OkexFuturesProduct.FromStr('BTC-USD.THIS_WEEK', trading_date),
      OkexFuturesProduct.FromStr('BTC-USD.NEXT_WEEK', trading_date),
      OkexFuturesProduct.FromStr('BTC-USD.QUARTER', trading_date),
  ])

  products.extend([
      HuobiFuturesProduct.FromStr('BTC-USD.THIS_WEEK', trading_date),
      HuobiFuturesProduct.FromStr('BTC-USD.NEXT_WEEK', trading_date),
      HuobiFuturesProduct.FromStr('BTC-USD.QUARTER', trading_date),
  ])

  products.extend([
      BitflyerFuturesProduct.FromStr("BTC-JPY.PERPETUAL"),
      BitflyerFuturesProduct.FromStr("BTC-JPY.IMMEDIATE"),
  ])

  # spot
  products.extend([
      # offshore
      BinanceProduct.FromStr("BTC-USDT"),
      OkexProduct.FromStr("BTC-USDT"),
      HuobiProduct.FromStr("BTC-USDT"),
      BitfinexProduct.FromStr("BTC-USDT"),
      HitbtcProduct.FromStr("BTC-USDT"),
      FcoinProduct.FromStr("BTC-USDT"),
      # korea
      BithumbProduct.FromStr("BTC-KRW"),
      UpbitProduct.FromStr("BTC-KRW"),
      # japan
      BitflyerFuturesProduct.FromStr("BTC-JPY"),
      QuoinexProduct.FromStr("BTC-JPY"),
      # us
      GdaxProduct.FromStr("BTC-USD"),
      KrakenProduct.FromStr("BTC-USD"),
  ])

  return products


def gen_okex_feed_sub_requests(trading_date, api_version):
  feed_sub_requests = []

  # Spot
  products = [
      OkexProduct.FromStr('BTC-USDT'),
      OkexProduct.FromStr('ETH-USDT'),
  ]
  for product in products:
    feed_sub_request = FeedSubscriptionRequest()
    feed_sub_request.add_products([product], SubscriptionRequest('Spot', 'Okex', api_version))
    feed_sub_requests.append(feed_sub_request)

  if api_version is None:  # v1 case.
    api_version = 'futures'

  # futures
  products = [
      OkexFuturesProduct.FromStr('BTC-USD.QUARTER', trading_date),
      OkexFuturesProduct.FromStr('ETH-USD.THIS_WEEK', trading_date),
  ]
  feed_sub_request = FeedSubscriptionRequest()
  feed_sub_request.add_products(products, SubscriptionRequest('Futures', 'Okex', api_version))
  feed_sub_requests.append(feed_sub_request)

  return feed_sub_requests


def gen_huobi_futures_feed_sub_requests(trading_date, api_version):
  feed_sub_requests = []

  products = [
      HuobiFuturesProduct.FromStr('BTC-USD.THIS_WEEK', trading_date),
      HuobiFuturesProduct.FromStr('BTC-USD.QUARTER', trading_date),
      HuobiFuturesProduct.FromStr('ETH-USD.THIS_WEEK', trading_date),
      HuobiFuturesProduct.FromStr('ETH-USD.QUARTER', trading_date),
      HuobiFuturesProduct.FromStr('BCHABC-USD.THIS_WEEK', trading_date),
      HuobiFuturesProduct.FromStr('BCHABC-USD.QUARTER', trading_date),
  ]
  feed_sub_request = FeedSubscriptionRequest()
  feed_sub_request.add_products(products, SubscriptionRequest('Futures', 'Huobi', api_version))
  feed_sub_requests.append(feed_sub_request)

  return feed_sub_requests


def gen_huobi_feed_sub_requests(trading_date, api_version):
  feed_sub_requests = []

  # Spot
  products = [
      HuobiProduct.FromStr('BTC-USDT'),
      HuobiProduct.FromStr('ETH-USDT'),
  ]
  feed_sub_request = FeedSubscriptionRequest()
  feed_sub_request.add_products(products, SubscriptionRequest('Spot', 'Huobi', api_version))
  feed_sub_requests.append(feed_sub_request)

  # Futures
  products = [
      HuobiFuturesProduct.FromStr('BTC-USD.QUARTER', trading_date),
      HuobiFuturesProduct.FromStr('ETH-USD.QUARTER', trading_date),
  ]
  feed_sub_request = FeedSubscriptionRequest()
  feed_sub_request.add_products(products, SubscriptionRequest('Futures', 'Huobi', api_version))
  feed_sub_requests.append(feed_sub_request)

  return feed_sub_requests


def gen_all_feed_sub_request(trading_date):
  feed_sub_request = FeedSubscriptionRequest()

  products = gen_all_products(trading_date)
  for product in products:
    feed_sub_request.add_products([product], get_subscription_key(product))

  okex_v3_futures_product_lists = get_exchange_product_list_grouped('Futures',
                                                                    'Okex',
                                                                    'v3',
                                                                    trading_date)
  for product_list in okex_v3_futures_product_lists:
    feed_sub_request.add_products(product_list, SubscriptionRequest('Futures', 'Okex', 'v3'))

  okex_v3_swap_product_lists = get_exchange_product_list_grouped('Futures',
                                                                 'Okex',
                                                                 'v3_swap',
                                                                 trading_date)
  for product_list in okex_v3_swap_product_lists:
    feed_sub_request.add_products(product_list, SubscriptionRequest('Futures', 'Okex', 'v3_swap'))
  return feed_sub_request


def gen_important_feed_sub_requests(trading_date):
  feed_sub_requests = []
  products = []

  for base in ('BTC',):
    products.extend([
        BitmexFuturesProduct.FromStr('%s-USD.PERPETUAL' % base),
    ])

  for base in ('BTC',):
    products.extend([
        HuobiFuturesProduct.FromStr('%s-USD.QUARTER' % base, trading_date),
    ])

  for base in ('BTC',):
    products.extend([
        DeribitFuturesProduct.FromStr('%s-USD.PERPETUAL' % base),
    ])

  for product in products:
    feed_sub_request = FeedSubscriptionRequest.create([product], get_subscription_key(product))
    feed_sub_requests.append(feed_sub_request)

  for base in ('BTC',):
    products = [
        OkexFuturesProduct.FromStr('%s-USD.QUARTER' % base, trading_date),
    ]
  feed_sub_request = FeedSubscriptionRequest()
  feed_sub_request.add_products(products, SubscriptionRequest('Futures', 'Okex', 'v3'))
  feed_sub_requests.append(feed_sub_request)

  for base in ('BTC',):
    products = [BinanceFuturesProduct.FromStr('%s-USDT.PERPETUAL' % base)]
  feed_sub_request = FeedSubscriptionRequest()
  feed_sub_request.add_products(products, SubscriptionRequest('Futures', 'Binance', None))
  feed_sub_requests.append(feed_sub_request)

  for base in ('BTC',):
    products = [BinanceProduct.FromStr('%s-USDT' % base)]
  feed_sub_request = FeedSubscriptionRequest()
  feed_sub_request.add_products(products, SubscriptionRequest('Spot', 'Binance', 'snapshot'))
  feed_sub_requests.append(feed_sub_request)

  return feed_sub_requests
